<template>
  <form :class="['el-form', {'el-form--inline': inline }]">
    <smart-form-group ref="form" :trigger="trigger" :object="object" :attach="attach" :model="model" :inline="inline">
      <slot></slot>
    </smart-form-group>

    <!-- 提交按钮 -->
    <el-row v-show="!hiddenButton" style="text-align: right">
      <el-col>
        <el-button size="small" type="primary" @click="submitForm" v-loading="loading" class="sea-form-submit"
                   element-loading-spinner="el-icon-loading">提交
        </el-button>
        <el-button size="small" @click="reset" v-loading="loading" class="sea-form-submit"
                   element-loading-spinner="el-icon-loading">重置
        </el-button>
      </el-col>
    </el-row>
  </form>
</template>

<script>
/* eslint-disable */
import SmartFormGroup from './smart-form-group'
import Layers from "@/lang/layers";

/**
 * 拒绝异常，因为一些已知的问题，拒绝提交表单
 */
class RejectException extends Error {
    constructor(message) {
        super(message);
        Object.setPrototypeOf(this, RejectException.prototype);
    }
}

/**
 * 通用表单界面
 *
 * 包含提交、重置按钮，能将表单配置数据，渲染成界面
 */
export default {
    components: {SmartFormGroup}
    , name: "SmartForm"
    , props: {
        // 表单模型
        model: {type: Array, default: undefined}
        // 表单类型：Standard（传统表单），FormData（一般包含文件），RequestBody（转JSON对象）
        , type: {type: String, default: 'Standard'}
        // 页面默认值，用于重置表单
        , object: {type: Object, default: undefined}
        // 触发器，用于处理表单内的数据联动
        , trigger: {type: Function, default: undefined}

        // 行内显示输入框
        , inline: {type: Boolean, default: false}

        // 表单提交的 ajax 基础参数配置
        , method: {type: String, default: 'POST'}
        // 表单提交的 ajax 基础参数配置
        , url: {type: String, default: undefined}
        // 表单附加参数，类似于Hidden，允许表单附加一些额外的固定参数
        , attach: {type: Object, default: undefined}

        // 提交表单前置拦截，如果不满足条件，可以阻止表单提交
        , onSubmit: {type: Function, default: undefined}
        // 操作成功后置操作，E.G.: 刷新界面，刷新表格
        , onSucceed: {type: Function, default: undefined}
        // 隐藏提交按钮
        , hiddenButton: {type: Boolean, default: false}
    }
    , data() {
        return {
            loading: false
        }
    }
    , created() {
        console.log(this.model);
    }
    , methods: {
        /**
         * 是否有效
         *
         * @return {boolean}
         */
        isValid: function () {
            return this.$refs.form.isValid();
        },
        /**
         * 序列化成FormData
         *
         * @return {FormData}
         */
        formData() {
            return this.$refs.form.formData();
        },
        /**
         * 序列化成FormData
         *
         * @return {object}
         */
        serialize() {
            return this.$refs.form.serialize();
        },
        /**
         * 设置新的值
         * @param value 对象
         */
        val: function (value) {
            this.$refs.form.val(value);
        },
        /**
         * 重置表单，注意这里不是清除表单
         */
        reset: function () {
            this.$refs.form.reset();
        },
        /**
         * 提交表单函数
         */
        submitForm: function () {
            if (this.loading) {
                return;
            }
            this.loading = true;
            this.submit().then(({ret, data}) => {
                this.loading = false;
                if (this.onSucceed !== undefined) {
                    this.onSucceed(ret, data);
                }
            }).catch(e => {
                this.loading = false;
                if (e instanceof RejectException) {
                    console.error(e.message);
                } else {
                    throw e;
                }
            });
        },
        /**
         * 提交表单函数，如果表单无效，或者未提交，会返回 undefined
         *
         * @return {Promise<*>}
         */
        submit: function () {
            console.log(this.serialize());
            return new Promise((resolve, reject) => {
                if (!this.isValid()) {
                    throw new RejectException('form is invalid!');
                }
                let data;
                if (this.type === 'Standard') {
                    // 普通方式提交
                    data = this.serialize();
                } else if (this.type === 'FormData') {
                    // FromData方式提交
                    data = this.formData();
                } else if (this.type === 'RequestBody') {
                    // RequestBody方式提交
                    data = this.serialize();
                }
                // 前置拦截，进行逻辑判断，根据内容决定是否提交
                if (Layers.isNotBlank(this.onSubmit) && this.onSubmit(data) === false) {
                    throw new RejectException('user canceled!');
                }

                // 构建表单提交参数
                let opts = {method: this.method, url: this.url};
                if (this.type === 'Standard') {
                    // 标准方式发送，功能与<form/>标签功能基本一致
                    opts.params = data;
                } else if (this.type === 'FormData') {
                    // 数据打包成FormData格式，以Post请求发送，功能与<form/>标签一致，特点是数据和文件可以同时上传

                    // 不要修改下面这一行代码，因为 FormData 只能由 POST 请求提交。
                    // 这属于Servlet默认规则，后端开发人员也不要尝试通过修改后台配置来解决这个问题。
                    opts.method = 'POST';
                    opts.data = data;
                } else if (this.type === 'RequestBody') {
                    // 以RequestBody的方式发送，可以提交一些很复杂的格式，数据会被转为JSON格式后提交
                    opts.data = data;
                }

            })
        }
    }
}
</script>

<style scoped>
</style>
